#include "View/OpenGL/OpenGLSupport.h"
#include "HObject.h"
#include "Window.h"
#include "GLWindow.h"
#include "View/OpenGL/OpenGLHelper.h"

namespace helix
{

	GLWindow::GLWindow(HINSTANCE hInstance, const char* title,int width,int height,int bpp,float fov,bool fullScreen) : Window(hInstance,title,width,height,bpp,fov,fullScreen)
	{
		this->renderHelper=NULL;
	}

	void GLWindow::initWindow()
	{
		//lets us know if anything went wrong while creating the widnow
		GLuint		pixelFormat;			// Holds The Results After Searching For A Match
		DWORD		dwExStyle;				// Window Extended Style
		DWORD		dwStyle;				// Window Style
		RECT		windowRect;				// Grabs Rectangle Upper Left / Lower Right Values
		windowRect.left=(long)0;			// Set Left Value To 0
		windowRect.right=(long)width;		// Set Right Value To Requested Width
		windowRect.top=(long)0;				// Set Top Value To 0
		windowRect.bottom=(long)height;		// Set Bottom Value To Requested Height

		created=false;

		if (fullScreen)												// Attempt Fullscreen Mode?
		{
			DEVMODE dmScreenSettings;								// Device Mode
			memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
			dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
			dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
			dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
			dmScreenSettings.dmBitsPerPel	= bpp;					// Selected Bits Per Pixel
			dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

			// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
			if (ChangeDisplaySettings(&dmScreenSettings,CDS_TEST)==DISP_CHANGE_BADMODE)
			{
				// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
				if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",title,MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
				{
					Log().Error("Could not create window in fullscreen mode.");
					fullScreen=false;		// Windowed Mode Selected.  Fullscreen = false
				}
				else
				{
					// Pop Up A Message Box Letting User Know The Program Is Closing.
					MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
					Log().Error("Could not create a window with the specified settings.");
					return;									// Return FALSE
				}
			}
			else
			{
				ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
			}
		}

		if (fullScreen)												// Are We Still In Fullscreen Mode?
		{
			dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
			dwStyle=WS_POPUP;										// Windows Style
			ShowCursor(false);										// Hide Mouse Pointer
		}
		else
		{
			dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
			dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style
		}

		AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle);		// Adjust Window To True Requested Size

		// Create The Window
		if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
									"Helix",							// Class Name
									title,								// Window Title
									dwStyle |							// Defined Window Style
									WS_CLIPSIBLINGS |					// Required Window Style
									WS_CLIPCHILDREN,					// Required Window Style
									0, 0,								// Window Position
									windowRect.right-windowRect.left,	// Calculate Window Width
									windowRect.bottom-windowRect.top,	// Calculate Window Height
									NULL,								// No Parent Window
									NULL,								// No Menu
									hInstance,							// Instance
									NULL)))								// Dont Pass Anything To WM_CREATE
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Could not create window.");
			return;										// Return FALSE
		}

		static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
		{
			sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
			1,											// Version Number
			PFD_DRAW_TO_WINDOW |						// Format Must Support Window
			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
			PFD_DOUBLEBUFFER,							// Must Support Double Buffering
			PFD_TYPE_RGBA,								// Request An RGBA Format
			bpp,										// Select Our Color Depth
			0, 0, 0, 0, 0, 0,							// Color Bits Ignored
			0,											// No Alpha Buffer
			0,											// Shift Bit Ignored
			0,											// No Accumulation Buffer
			0, 0, 0, 0,									// Accumulation Bits Ignored
			bpp,										// 16Bit Z-Buffer (Depth Buffer)  
			0,											// No Stencil Buffer
			0,											// No Auxiliary Buffer
			PFD_MAIN_PLANE,								// Main Drawing Layer
			0,											// Reserved
			0, 0, 0										// Layer Masks Ignored
		};
		
		if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Could not create an OpenGL device context.");
			return;								// Return FALSE
		}

		if (!(pixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Coulnd not find a pixel format for the device context.");
			return;								// Return FALSE
		}

		if(!SetPixelFormat(hDC,pixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Could not set the pixel format.");
			return;								// Return FALSE
		}

		if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Could not create an OpenGL rendering context.");
			return;								// Return FALSE
		}

		if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
		{
			killWindow();								// Reset The Display
			MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
			Log().Error("Could not activate the OpenGL rendering context.");
			return;								// Return FALSE
		}

		renderHelper = new OpenGLHelper();

		created=true;				//success
	}

	GLWindow::~GLWindow()
	{
		if(renderHelper)
			delete renderHelper;

		killWindow();
	}

	void GLWindow::toggleFullScreen()
	{

	}
		
	void GLWindow::setFullScreen(bool fullScreen)
	{
		if(fullScreen==this->fullScreen && this->created)
			return;
		else
			toggleFullScreen();
	}


	bool GLWindow::isCreated()
	{
		return this->created;
	}

	void GLWindow::killWindow()
	{
		if (fullScreen)										// Are We In Fullscreen Mode?
		{
			ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
			ShowCursor(TRUE);								// Show Mouse Pointer
		}

		if (hRC)											// Do We Have A Rendering Context?
		{
			if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
			{
				MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
				Log().Error("Could not release device and rendering contexts.");
			}

			if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
			{
				MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
				Log().Error("Could not release rendering context.");
			}
			hRC=NULL;										// Set RC To NULL
		}

		if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
		{
			MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			Log().Error("Could not release device context.");
			hDC=NULL;										// Set DC To NULL
		}

		if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
		{
			MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
			Log().Error("Could not destroy window.");
			hWnd=NULL;										// Set hWnd To NULL
		}
	}

	void GLWindow::changeWindowParams(int width,int height,float fov)
	{
		this->width=width;
		this->width=height;
		this->fov=fov;
	}

	void GLWindow::setWindowParams(int width,int height)
	{
		this->width=width;
		this->height=height;
	}

	void GLWindow::resizeScene()
	{
		if (height<=0)										// Prevent A Divide By Zero By
		{
			height=1;										// Making Height Equal One
		}
		if (width<=0)
		{
			width=1;
		}

		glViewport(0,0,width,height);						// Reset The Current Viewport

		glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
		glLoadIdentity();									// Reset The Projection Matrix

		// Calculate The Aspect Ratio Of The Window
		gluPerspective(fov,(GLfloat)width/(GLfloat)height,nearClip,farClip);

		glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
		glLoadIdentity();									// Reset The Modelview Matrix
	}

}